home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / ADVANCED / SGIFLAG.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  11.8 KB  |  489 lines

  1.  
  2. /*
  3.  *    sgiflag.c:
  4.  *
  5.  *  This program displays a waving flag with an SGI logo trimmed out of
  6.  *  it.  The flag is a single nurbs surface (bicubic, bezier). It "waves" 
  7.  *  by making it control point oscillate on a sine wave.
  8.  *
  9.  *  The logo is cut from the flag using a combination of piecewise-linear 
  10.  *  and bezier trim curves.
  11.  *
  12.  *                                    Howard Look - December 1990
  13.  *                      David Blythe - June 1995
  14.  */
  15.  
  16. #include <GL/glut.h>
  17.  
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20.  
  21. #include <math.h>
  22. #include "sgiflag.h"
  23. #include "logopoints.h"
  24.  
  25. /* Some <math.h> files do not define M_PI... */
  26. #ifndef M_PI
  27. #define M_PI 3.14159265358979323846
  28. #endif
  29.  
  30. /* Knot sequences for cubic bezier surface and trims */
  31. Knot sknots[S_NUMKNOTS] = {0., 0., 0., 0., 1., 1., 1., 1.};
  32. Knot tknots[T_NUMKNOTS] = {0., 0., 0., 0., 1., 1., 1., 1.};
  33. Knot trimknots[S_NUMKNOTS] = {0., 0., 0., 0., 1., 1., 1., 1.};
  34.  
  35. /* Control points for the flag. The Z values are modified to make it wave */
  36. Point ctlpoints[S_NUMPOINTS][T_NUMPOINTS] = {
  37.     { {0., 3., 0.}, {1., 3., 0.}, {2., 3., 0}, {3., 3., 0.}},
  38.     { {0., 2., 0.}, {1., 2., 0.}, {2., 2., 0}, {3., 2., 0.}},
  39.     { {0., 1., 0.}, {1., 1., 0.}, {2., 1., 0}, {3., 1., 0.}},
  40.     { {0., 0., 0.}, {1., 0., 0.}, {2., 0., 0}, {3., 0., 0.}}
  41. };
  42.  
  43. /* Trim the whole exterior of the, counter clockwise. Necessary to do
  44.  * internal trimming
  45.  */
  46. TrimCurve *whole;
  47. TrimCurve ccl_path;
  48. TrimPiece ccl_square[] = {
  49.     {
  50.         PWL,
  51.         11,
  52.         {
  53.             {0., 0.}, {.25, 0.}, {.5, 0.}, {.75, 0.}, {1., 0.},
  54.             {1., 1.}, {.75, 1.}, {.5, 1.}, {.25, 1.}, {0., 1.}, {0., 0.}
  55.         }
  56.     }
  57. };
  58.  
  59. /* Three paths for three parts of the logo */
  60. TrimCurve *path[3];
  61.  
  62. /* Initial one-third of the logo, centered at origin */
  63. TrimCurve initial_path;
  64. TrimPiece initial_pieces[] = {
  65.         {
  66.             PWL, /* 0 */
  67.             6,
  68.             {{Ax,Ay},{Bx,By},{Cx,Cy},{Dx,Dy},{Ex,Ey},{0.,0.}}
  69.         },
  70.         {
  71.             CURVE, /* 1 */
  72.             4,
  73.             {{0.,0.},{Fx,Fy},{Fx,Fy},{0.,0.}}
  74.         },
  75.         {
  76.             PWL, /* 2 */
  77.             2,
  78.             {{Gx, Gy},{Gx,Gy}}
  79.         },
  80.         {
  81.             CURVE, /* 3 */
  82.             4,
  83.             {{0.,0.},{Gx,Gy},{Gx,Gy},{0.,0.}}
  84.         },
  85.         {
  86.             PWL, /* 4 */
  87.             3,
  88.             {{0., 0.},{Z,Z},{0.,0.}}
  89.         },
  90.         {
  91.             CURVE, /* 5 */
  92.             4,
  93.             {{0.,0.},{-Gx,Gy},{-Gx,Gy},{0.,0.}}
  94.         },
  95.         {
  96.             PWL, /* 6 */
  97.             2,
  98.             {{-Fx, Fy},{-Fx,Fy}}
  99.         },
  100.         {
  101.             CURVE, /* 7 */
  102.             4,
  103.             {{0.,0.},{-Fx,Fy},{-Fx,Fy},{0.,0.}}
  104.         },
  105.         {
  106.             PWL, /* 8 */
  107.             6,
  108.             {{0.,0.},{-Ex,Ey},{-Dx,Dy},{-Cx,Cy},{-Bx,By},{Ax,Ay}}
  109.         }
  110. };
  111.  
  112. static GLUnurbsObj *nurbsflag;
  113.  
  114. static GLboolean trimming = GL_TRUE, filled = GL_TRUE, hull = GL_TRUE;
  115. static int mousex = 248, mousey = 259, mstate;
  116.  
  117. /* Given endpoints of the line a and b, the distance d from point a,
  118.  * returns a new point (in result) that is on that line.
  119.  */
  120. void interp(TrimPoint a, TrimPoint b, GLfloat d, TrimPoint result) {
  121.  
  122.     GLfloat l;
  123.  
  124.     l = sqrt((a[0] - b[0])*(a[0] - b[0]) + (a[1] - b[1])*(a[1] - b[1]));
  125.  
  126.     result[0] = a[0] + (b[0] - a[0])*d/l; 
  127.     result[1] = a[1] + (b[1] - a[1])*d/l; 
  128.     
  129. }
  130.  
  131. /* Given two trim pieces, coerces the endpoint of the first and the
  132.  * start point of the second to be indentical.
  133.  *
  134.  * The two trims must be of opposite types, PWL or CURVE.
  135.  */
  136. void join_trims(TrimPiece *trim1, TrimPiece *trim2, GLfloat radius) {
  137.  
  138.     int last;
  139.     TrimPoint result;
  140.  
  141.     last = trim1->points - 1;
  142.     
  143.     if (trim1->type == PWL)
  144.         interp(trim2->point[1], trim1->point[last - 1], radius, result);
  145.     else /* trim1 is CURVE */
  146.         interp(trim1->point[last-1], trim2->point[0], radius, result);
  147.  
  148.     trim1->point[last][0] = trim2->point[0][0] = result[0];
  149.     trim1->point[last][1] = trim2->point[0][1] = result[1];
  150. }    
  151.  
  152. /* Translates each point in the trim piece by tx and ty */
  153. void translate_trim(TrimPiece *trim, GLfloat tx, GLfloat ty) {
  154.  
  155.     int i;
  156.  
  157.     for (i=0; i<trim->points; i++) {
  158.         trim->point[i][0] += tx;
  159.         trim->point[i][1] += ty;
  160.     }
  161. }        
  162.  
  163. /* Scales each point in the trim piece by sx and sy */
  164. void scale_trim(TrimPiece *trim, GLfloat sx, GLfloat sy) {
  165.  
  166.     int i;
  167.  
  168.     for (i=0; i<trim->points; i++) {
  169.         trim->point[i][0] *= sx;
  170.         trim->point[i][1] *= sy;
  171.     }
  172. }        
  173.  
  174. /* Rotates each point in the trim piece by angle radians about the origin */
  175. void rotate_trim(TrimPiece *trim, GLfloat angle) {
  176.  
  177.     int i;
  178.     GLfloat s,c;
  179.     TrimPoint t;
  180.  
  181.     s = sin(angle);
  182.     c = cos(angle);
  183.  
  184.     for (i=0; i<trim->points; i++) {
  185.         t[0] = trim->point[i][0];
  186.         t[1] = trim->point[i][1];
  187.         
  188.         trim->point[i][0] = c*t[0] - s*t[1];
  189.         trim->point[i][1] = s*t[0] + c*t[1];
  190.     }
  191. }        
  192.  
  193. /* Creates storage space for dst and copies the contents of src into dst */
  194. void copy_path(TrimCurve *src, TrimCurve **dst) {
  195.  
  196.     int i,j;
  197.  
  198.     *dst = (TrimCurve *) malloc(sizeof(TrimCurve));
  199.     (*dst)->pieces = src->pieces;
  200.     (*dst)->trim = (TrimPiece *) malloc((src->pieces)*sizeof(TrimPiece));
  201.  
  202.     for(i=0; i < src->pieces; i++) {
  203.         (*dst)->trim[i].type = src->trim[i].type;
  204.         (*dst)->trim[i].points = src->trim[i].points;
  205.  
  206.         for (j=0; j < src->trim[i].points; j++) {
  207.             (*dst)->trim[i].point[j][0] = src->trim[i].point[j][0];
  208.             (*dst)->trim[i].point[j][1] = src->trim[i].point[j][1];
  209.         }
  210.     }
  211. }    
  212.  
  213. /* Initializes the outer whole trim plus the three trimming paths 
  214.  * required to trim the logo.
  215.  */
  216. void init_trims(void) {
  217.  
  218.     int i;
  219.  
  220.     /* whole outer path, counter clockwise, so NuRB is not trimmed */
  221.     whole = &ccl_path;
  222.     whole->pieces = 1;
  223.     whole->trim = ccl_square;
  224.  
  225.     /* initial third of logo, centered at origin */
  226.     path[0] = &initial_path;
  227.     path[0]->pieces = ELEMENTS(initial_pieces);
  228.     path[0]->trim = initial_pieces;
  229.     for(i=0; i < path[0]->pieces - 1; i++)
  230.         join_trims(&path[0]->trim[i], &path[0]->trim[i+1], LOGO_RADIUS);
  231.  
  232.     /* copy other to other two thirds */
  233.     copy_path(path[0],&path[1]);
  234.     copy_path(path[0],&path[2]);
  235.  
  236.     /* scale and translate first third */
  237.     for (i=0; i<path[0]->pieces; i++) {
  238.         scale_trim(&path[0]->trim[i],0.5,1.0);
  239.         translate_trim(&path[0]->trim[i],0.5,0.52);
  240.     }
  241.  
  242.     /* rotate, scale and translate second third */
  243.     for (i=0; i<path[1]->pieces; i++) {        
  244.         rotate_trim(&path[1]->trim[i],2.0*M_PI/3.0);
  245.         scale_trim(&path[1]->trim[i],0.5,1.0);
  246.         translate_trim(&path[1]->trim[i],0.49,0.5);
  247.     }
  248.  
  249.     /* rotate, scale and translate last third */
  250.     for (i=0; i<path[2]->pieces; i++) {        
  251.         rotate_trim(&path[2]->trim[i],2.0*2.0*M_PI/3.0);
  252.         scale_trim(&path[2]->trim[i],0.5,1.0);
  253.         translate_trim(&path[2]->trim[i],0.51,0.5);
  254.     }
  255. }
  256.     
  257. /* Opens a square window, and initializes the window, interesting devices,
  258.  * viewing volume, material, and lights.
  259.  */
  260. static void
  261. initialize(void) {
  262.  
  263.     GLfloat mat_diffuse[] = { .8, .1, .8, 1. };
  264.     GLfloat mat_specular[] = { .6, .6, .6, 1. };
  265.     GLfloat mat_ambient[] = { .1, .1, .1, 1. };
  266.  
  267.     glClearColor(.58, .58, .58, 0.);
  268.     glClearDepth(1.);
  269.     glEnable(GL_DEPTH_TEST);
  270.  
  271.     glMatrixMode(GL_PROJECTION);
  272.     gluPerspective(60,1.0,1.0,10.0);
  273.     glMatrixMode(GL_MODELVIEW);
  274.     glTranslatef(0., 0., -6.);
  275.     
  276.     glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
  277.     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
  278.     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
  279.     glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 32.0);
  280.     glEnable(GL_LIGHT0);
  281.     glEnable(GL_LIGHTING);
  282.     glEnable(GL_AUTO_NORMAL);
  283.     glEnable(GL_NORMALIZE);
  284.  
  285.     nurbsflag = gluNewNurbsRenderer();
  286.     gluNurbsProperty(nurbsflag, GLU_SAMPLING_TOLERANCE, 100.0);
  287.     gluNurbsProperty(nurbsflag, GLU_DISPLAY_MODE, GLU_FILL);
  288.  
  289.     init_trims();
  290. }
  291.  
  292.  
  293. /* Draw the nurb, possibly with trimming */
  294. void draw_nurb(GLboolean trimming) {
  295.  
  296.     static GLfloat angle = 0.0;
  297.     int i,j;
  298.  
  299.  
  300.     /* wave the flag by rotating Z coords though a sine wave */
  301.     for (i=1; i<4; i++)
  302.         for (j=0; j<4; j++)
  303.             ctlpoints[i][j][2] = sin((GLfloat)i+angle);
  304.  
  305.     angle += 0.1;
  306.     
  307.     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  308.  
  309.     glPushMatrix();
  310.  
  311.         glTranslatef(2.5,-1.0,0.0);
  312.         glScalef(1.5,1.0,1.0);
  313.         glRotatef(90,0.,0.,1.);
  314.         glRotatef(mousey/10.,1.,0.,0.);
  315.         glRotatef(mousex/10.,0.,1.,0.);
  316.         
  317.     gluBeginSurface(nurbsflag);
  318.             gluNurbsSurface(nurbsflag,S_NUMKNOTS, sknots, T_NUMKNOTS, tknots,
  319.                           3 * T_NUMPOINTS, 3,
  320.                           &ctlpoints[0][0][0], T_ORDER, S_ORDER, GL_MAP2_VERTEX_3);
  321.             if (trimming) {
  322.                 dotrim(whole);
  323.                 dotrim(path[0]);
  324.                 dotrim(path[1]);
  325.                 dotrim(path[2]);
  326.             }
  327.         gluEndSurface(nurbsflag);
  328.         
  329.     if (hull) draw_hull(ctlpoints);
  330.     
  331.     glPopMatrix();
  332.     
  333. }
  334.  
  335. /* Draw the convex hull of the control points */
  336. void draw_hull(Point cpoints[S_NUMPOINTS][T_NUMPOINTS]) {
  337.  
  338.     int s,t;
  339.     
  340.     glDisable(GL_LIGHTING);
  341.     glColor3f(0.,1.,0.);
  342.  
  343.     glBegin(GL_LINES);
  344.     for (s=0; s<S_NUMPOINTS; s++)
  345.         for (t=0; t<T_NUMPOINTS-1; t++) {
  346.                 glVertex3fv(cpoints[s][t]);
  347.                 glVertex3fv(cpoints[s][t+1]);
  348.         }
  349.         
  350.     for (t=0; t<T_NUMPOINTS; t++)
  351.         for (s=0; s<S_NUMPOINTS-1; s++) {
  352.                 glVertex3fv(cpoints[s][t]);
  353.                 glVertex3fv(cpoints[s+1][t]);
  354.         }
  355.     glEnd();
  356.     glEnable(GL_LIGHTING);
  357. }
  358.  
  359.  
  360. /* Execute a bgn/endtrim pair for the given trim curve structure. */
  361. void dotrim(TrimCurve *trim_curve) {
  362.  
  363.     int i;
  364.  
  365.     gluBeginTrim(nurbsflag);
  366.         for (i=0; i<trim_curve->pieces; i++) {
  367.  
  368.             if (trim_curve->trim[i].type == PWL) {
  369.                     gluPwlCurve(nurbsflag, trim_curve->trim[i].points,
  370.                               &trim_curve->trim[i].point[0][0],
  371.                               2, GLU_MAP1_TRIM_2);
  372.             } else {
  373.                 gluNurbsCurve(nurbsflag, ELEMENTS(trimknots),trimknots,
  374.                             2,&trim_curve->trim[i].point[0][0],
  375.                             trim_curve->trim[i].points, GLU_MAP1_TRIM_2);
  376.             }
  377.         }
  378.     gluEndTrim(nurbsflag);
  379. }
  380.  
  381.  
  382. /* ARGSUSED1 */
  383. static void
  384. Key(unsigned char c, int x, int y)
  385. {
  386.     switch(c) {
  387.     case 27: /* Escape */
  388.     exit(0);
  389.     break;
  390.     default:
  391.     break;
  392.     }
  393. }
  394.  
  395. static void
  396. Button(int button, int down, int x, int y)
  397. {
  398.     if (down) {
  399.     if (button == GLUT_LEFT_BUTTON) {
  400.         mstate = 1;
  401.         mousex = x;
  402.         mousey = y;
  403.     }
  404.     } else {
  405.     if (button == GLUT_LEFT_BUTTON)
  406.         mstate = 0;
  407.     }
  408.     if (mstate) {
  409.     mousex = x;
  410.     mousey = y;
  411.     }
  412. }
  413.  
  414. static void
  415. resize(int width, int height)
  416. {
  417.    glViewport(0, 0, width, height);
  418. }
  419.  
  420.  
  421. static void
  422. expose(void)
  423. {
  424.     draw_nurb(trimming);
  425.     glutSwapBuffers();
  426. }
  427.  
  428. static void
  429. idle(void)
  430. {
  431.   glutPostRedisplay();
  432. }
  433.  
  434. static void
  435. visibility(int state)
  436. {
  437.   if (state == GLUT_VISIBLE) {
  438.     glutIdleFunc(idle);
  439.   } else {
  440.     glutIdleFunc(NULL);
  441.   }
  442. }
  443.  
  444. static void
  445. Menu(int value)
  446. {
  447.     switch (value) {
  448.     case 1:
  449.     trimming ^= 1; break;
  450.     case 2:
  451.     filled ^= 1;
  452.     gluNurbsProperty(nurbsflag, GLU_DISPLAY_MODE,
  453.              filled ? GLU_FILL : GLU_OUTLINE_POLYGON);
  454.     break;
  455.     case 3:
  456.     hull ^= 1; break;
  457.     case 4:
  458.     exit(0); break;
  459.     default:
  460.     break;
  461.     }
  462. }
  463.  
  464. int
  465. main(int argc, char *argv[])
  466. {
  467.     glutInit(&argc, argv);
  468.     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
  469.     glutInitWindowSize(400, 400);
  470.     glutCreateWindow("NURBS Surface");
  471.     glutDisplayFunc(expose);
  472.     glutReshapeFunc(resize);
  473.     glutKeyboardFunc(Key);
  474.     glutMouseFunc(Button);
  475.  
  476.     glutCreateMenu(Menu);
  477.     glutAddMenuEntry("Trim", 1);
  478.     glutAddMenuEntry("Fill", 2);
  479.     glutAddMenuEntry("Hull", 3);
  480.     glutAddMenuEntry("Exit", 4);
  481.     glutAttachMenu(GLUT_RIGHT_BUTTON);
  482.     glutVisibilityFunc(visibility);
  483.  
  484.     initialize();
  485.  
  486.     glutMainLoop();
  487.     return 0;
  488. }
  489.